package com.coldwindblows.blog.controller;

import java.net.URLEncoder;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.coldwindblows.blog.bo.ArchiveBo;
import com.coldwindblows.blog.bo.CommentBo;
import com.coldwindblows.blog.bo.RestResponseBo;
import com.coldwindblows.blog.constant.WebConst;
import com.coldwindblows.blog.dto.ErrorCode;
import com.coldwindblows.blog.dto.MetaDto;
import com.coldwindblows.blog.dto.Types;
import com.coldwindblows.blog.pojo.CommentDo;
import com.coldwindblows.blog.pojo.ContentDo;
import com.coldwindblows.blog.pojo.MetaDo;
import com.coldwindblows.blog.service.ICommentService;
import com.coldwindblows.blog.service.IContentService;
import com.coldwindblows.blog.service.IMetaService;
import com.coldwindblows.blog.service.ISiteService;
import com.coldwindblows.blog.utils.IPKit;
import com.coldwindblows.blog.utils.PatternKit;
import com.coldwindblows.blog.utils.TaleUtils;
import com.github.pagehelper.PageInfo;
import com.vdurmont.emoji.EmojiParser;

/**
 * 首页
 * Created by ColdWindBlows on 2018/07/05
 */
@Controller
@SuppressWarnings("rawtypes")
public class IndexController extends BaseController {
	
	@Autowired
	private IContentService contentService;
	
	@Autowired
	private ICommentService commentService;
	
	@Autowired
	private IMetaService metaService;
	
	@Autowired
	private ISiteService siteService;
	
	/**
	 * 首页
	 * @return
	 */
	@GetMapping(value = "/")
	public String index(HttpServletRequest request, @RequestParam(value = "limit", defaultValue= "12") int limit) {
		return this.index(request, 1, limit);
	}
	
	/**
	 * 首页分页
	 * @param request
	 * @param p 第几页
	 * @param limit 每页大小
	 * @return
	 */
	@GetMapping("/page/{p}")
	public String index(HttpServletRequest request, @PathVariable("p") int p, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		p = p < 0 || p > WebConst.MAX_PAGE ? 1 : p;
		PageInfo<ContentDo> articles = contentService.getContents(p, limit);
		request.setAttribute("articles", articles);
		if(p > 1) {
			this.title(request, "第" + p + "页");
		}
		
		return this.render("index");
	}
	
	/**
	 * 文章页
	 * @param request
	 * @param cid
	 * @return
	 */
	@GetMapping({"/article/{cid}", "/article/{cid}.html"})
	public String getArticle(HttpServletRequest request, @PathVariable("cid")String cid) {
		ContentDo content = contentService.getDetail(cid);
		if(null == content || "draft".equals(content.getStatus())) {
			return this.render_404();
		}
		request.setAttribute("article", content);
		request.setAttribute("is_post", true);
		completeArticle(request, content);
		if(!checkHitsFrequency(request, cid)) {
			updateArticleHit(content.getCid(), content.getHits());
		}
		
		return this.render("post");
	}
	
	/**
	 * 文章页（预览）
	 * @param request
	 * @param cid
	 * @return
	 */
	@GetMapping({"/article/{cid}/preview", "/article/{cid}.html"})
	public String articlePreview(HttpServletRequest request, @PathVariable("cid")String cid) {
		ContentDo content = contentService.getDetail(cid);
		if(null == content) {
			return this.render_404();
		}
		request.setAttribute("article", content);
		request.setAttribute("is_post", true);
		completeArticle(request, content);
		if(!checkHitsFrequency(request, cid)) {
			updateArticleHit(content.getCid(), content.getHits());
		}
		return this.render("post");
	}
	
	/**
	 * 抽取公共方法
	 * @param request
	 * @param content
	 */
	private void completeArticle(HttpServletRequest request, ContentDo content) {
		if(content.getAllowComment()) {
			String cp = request.getParameter("cp");
			if(StringUtils.isBlank(cp)) {
				cp = "1";
			}
			request.setAttribute("cp", cp);
			PageInfo<CommentBo> commentPaginator = commentService.getComments(content.getCid(), Integer.parseInt(cp), 6);
			request.setAttribute("comments", commentPaginator);
		}
	}
	
	/**
	 * 注销
	 * @param session
	 * @param response
	 */
	@RequestMapping("/logout")
	public void logout(HttpSession session, HttpServletResponse response) {
		TaleUtils.logout(session, response);
	}
	
	/**
	 * 评论操作
	 * @param request
	 * @param response
	 * @param cid
	 * @param coid
	 * @param author
	 * @param mail
	 * @param url
	 * @param text
	 * @param _csrf_token
	 * @return
	 */
	@PostMapping("/comment")
	@ResponseBody
	public RestResponseBo comment(HttpServletRequest request, HttpServletResponse response, Integer cid, Integer coid, String author, String mail, String url, String text, String _csrf_token) {
		String ref = request.getHeader("Referer");
		if(StringUtils.isBlank(ref) || StringUtils.isBlank(_csrf_token)) {
			return RestResponseBo.fail(ErrorCode.BAD_RQQUEST);
		}
		
		String token = cache.hget(Types.CSRF_TOKEN.getType(), _csrf_token);
		if(StringUtils.isBlank(token)) {
			return RestResponseBo.fail(ErrorCode.BAD_RQQUEST);
		}
		
		if(null == cid || StringUtils.isBlank(text)) {
			return RestResponseBo.fail("请输入完整后评论");
		}
		
		if(StringUtils.isNotBlank(author) && author.length() > 50) {
			return RestResponseBo.fail("姓名过长");
		}
		
		if(StringUtils.isNotBlank(mail) && !TaleUtils.isEmail(mail)) {
			return RestResponseBo.fail("请输入正确的邮箱格式");
		}
		
		if(StringUtils.isNotBlank(url) && !PatternKit.isURL(url)) {
			return RestResponseBo.fail("请输入正确的URL格式");
		}
		
		if(text.length() > 200) {
			return RestResponseBo.fail("请输入200个字符以内的评论");
		}
		
		String val = IPKit.getIpAddrByRequest(request) + ":" + cid;
		Integer count = cache.hget(Types.COMMENTS_FREQUENCY.getType(), val);
		if(null != count && count > 0) {
			return RestResponseBo.fail("您发表评论太快了，请过会再试");
		}
		
		author = TaleUtils.cleanXSS(author);
		text = TaleUtils.cleanXSS(text);
		
		author = EmojiParser.parseToAliases(author);
		text = EmojiParser.parseToAliases(text);
		
		CommentDo comment = new CommentDo();
		comment.setAuthor(author);
		comment.setContent(text);
		comment.setCid(cid);
		comment.setIp(request.getRemoteAddr());
		comment.setUrl(url);
		comment.setMail(mail);
		comment.setParent(coid);
		try {
			String result = commentService.insertComment(comment);
			cookie("tale_remember_author", URLEncoder.encode(author, "UTF-8"), 7 * 24 * 60 * 60, response);
			cookie("tale_remember_mail", URLEncoder.encode(mail, "UTF-8"), 7 * 24 * 60 * 60, response);
			if(StringUtils.isNotBlank(url)) {
				cookie("tale_remember_url", URLEncoder.encode(url, "UTF-8"), 7 * 24 * 60 * 60, response);
			}
			
			// 设置对每个文章1分钟可以评论一次
			cache.hset(Types.COMMENTS_FREQUENCY.getType(), val, 1, 60);
			if(!WebConst.SUCCESS_RESULT.equals(result)) {
				return RestResponseBo.fail(result);
			}
			return RestResponseBo.ok();
		} catch(Exception e) {
			String msg = "评论发布失败";
			return RestResponseBo.fail(msg);
		}
	}
	
	/**
	 * 分类页
	 * @param request
	 * @param keyword
	 * @param limit
	 * @return
	 */
	@GetMapping("/category/{keyword}")
	public String categories(HttpServletRequest request, @PathVariable("keyword")String keyword, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		return this.categories(request, keyword, 1, limit);
	}
	
	@GetMapping("/category/{keyword}/{page}")
	public String categories(HttpServletRequest request, @PathVariable("keyword")String keyword, @PathVariable("page")int page, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		page = page < 0 || page > WebConst.MAX_PAGE ? 1 : page;
		MetaDto metaDto = metaService.getMeta(Types.CATEGORY.getType(), keyword);
		if(null == metaDto) {
			return this.render_404();
		}
		
		PageInfo<ContentDo> pageList = contentService.getArticles(metaDto.getMid(), page, limit);
		request.setAttribute("articles", pageList);
		request.setAttribute("meta", metaDto);
		request.setAttribute("type", "分类");
		request.setAttribute("keyword", keyword);
		
		return this.render("page-category");
	}
	
	/**
	 * 归档页
	 * @param request
	 * @return
	 */
	@GetMapping("/archives")
	public String archives(HttpServletRequest request) {
		List<ArchiveBo> archives = siteService.getArchives();
		request.setAttribute("archives", archives);
		return this.render("archives");
	}
	
	/**
	 * 友链页
	 * @param request
	 * @return
	 */
	@GetMapping("/links")
	public String links(HttpServletRequest request) {
		List<MetaDo> links = metaService.getMetas(Types.LINK.getType());
		request.setAttribute("links", links);
		return this.render("links");
	}
	
	/**
	 * 自定义页面，如关于页面
	 * @param pagename
	 * @param request
	 * @return
	 */
	@GetMapping("/{pagename}")
	public String page(@PathVariable("pagename")String pagename, HttpServletRequest request) {
		ContentDo content = contentService.getDetail(pagename);
		if(null == content) {
			return this.render_404();
		}
		if(content.getAllowComment()) {
			String cp = request.getParameter("cp");
			if(StringUtils.isBlank(cp)) {
				cp = "1";
			}
			PageInfo<CommentBo> pageList = commentService.getComments(content.getCid(), Integer.parseInt(cp), 6);
			request.setAttribute("comments", pageList);
		}
		request.setAttribute("article", content);
		if(!checkHitsFrequency(request, String.valueOf(content.getCid()))) {
			updateArticleHit(content.getCid(), content.getHits());
		}
		return this.render("page");
	}
	
	/**
	 * 搜索页
	 * @param request
	 * @param keyword
	 * @param limit
	 * @return
	 */
	@GetMapping("/search/{keyword}")
	public String search(HttpServletRequest request, @PathVariable("keyword")String keyword, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		return this.search(request, keyword, 1, limit);
	}
	
	@GetMapping("/search/{keyword}/{page}")
	public String search(HttpServletRequest request, @PathVariable("keyword")String keyword, @PathVariable("page")int page, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		page = page < 0 || page > WebConst.MAX_PAGE ? 1 : page;
		PageInfo<ContentDo> articles = contentService.getArticles(keyword, page, limit);
		request.setAttribute("articles", articles);
		request.setAttribute("type", "搜索");
		request.setAttribute("keyword", keyword);
		return this.render("page-category");
	}
	
	/**
	 * 更新文章的点击率
	 * @param cid
	 * @param chits
	 */
	private void updateArticleHit(Integer cid, Integer chits) {
		Integer hits = cache.hget("article" + cid, "hits");
		if(chits == null) {
			chits = 0;
		}
		hits = null == hits ? 1 : hits + 1;
		if(hits >= WebConst.HIT_EXCEED) {
			ContentDo temp = new ContentDo();
			temp.setCid(cid);
			temp.setHits(chits + hits);
			contentService.updateContent(temp);
			cache.hset("article" + cid, "hits", 1);
		} else {
			cache.hset("article" + cid, "hits", hits);
		}
	}
	
	/**
	 * 标签页
	 * @param request
	 * @param name
	 * @param limit
	 * @return
	 */
	@GetMapping("/tag/{name}")
	public String tags(HttpServletRequest request, @PathVariable("name")String name, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		return this.tags(request, name, 1, limit);
	}
	
	@GetMapping("/tag/{name}/{page}")
	public String tags(HttpServletRequest request, @PathVariable("name")String name, @PathVariable("page")int page, @RequestParam(value = "limit", defaultValue = "12")int limit) {
		page = page < 0 || page > WebConst.MAX_PAGE ? 1 : page;
		name = name.replaceAll("\\+", " ");
		MetaDto metaDto = metaService.getMeta(Types.TAG.getType(), name);
		if(null == metaDto) {
			return this.render_404();
		}
		
		PageInfo<ContentDo> pageList = contentService.getArticles(metaDto.getMid(), page, limit);
		request.setAttribute("articles", pageList);
		request.setAttribute("meta", metaDto);
		request.setAttribute("type", "标签");
		request.setAttribute("keyword", name);
		
		return this.render("page-category");
	}
	
	/**
	 * 设置cookie
	 * @param name
	 * @param value
	 * @param maxAge
	 * @param response
	 */
	private void cookie(String name, String value, int maxAge, HttpServletResponse response) {
		Cookie cookie = new Cookie(name, value);
		cookie.setMaxAge(maxAge);
		cookie.setSecure(false);
		response.addCookie(cookie);
	}
	
	/**
	 * 检查同一个ip地址是否在2小时内访问同一文章
	 * @param request
	 * @param cid
	 * @return
	 */
	private boolean checkHitsFrequency(HttpServletRequest request, String cid) {
		String val = IPKit.getIpAddrByRequest(request) + ":" + cid;
		Integer count = cache.hget(Types.HITS_FREQUENCY.getType(), val);
		if(null != count && count > 0) {
			return true;
		}
		cache.hset(Types.HITS_FREQUENCY.getType(), val, 1, WebConst.HITS_LIMIT_TIME);
		return false;
	}
}
